package com.cqupt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqupt.exception.BusinessException;
import com.cqupt.mapper.SceneDetailMapper;
import com.cqupt.mapper.SceneRecordMapper;
import com.cqupt.mapper.ScoreRecordMapper;
import com.cqupt.model.dto.SceneDto;
import com.cqupt.model.pojo.Scene;
import com.cqupt.model.pojo.SceneDetail;
import com.cqupt.model.pojo.SceneRecord;
import com.cqupt.model.pojo.ScoreRecord;
import com.cqupt.model.vo.*;
import com.cqupt.service.SceneService;
import com.cqupt.mapper.SceneMapper;
import com.cqupt.service.SparkService;
import com.cqupt.utils.AudioUtil;
import com.cqupt.utils.AuthContextUtil;
import com.cqupt.utils.MachineTranslationUtil;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


@Service
public class SceneServiceImpl extends ServiceImpl<SceneMapper, Scene>
        implements SceneService {

    @Resource
    private SceneMapper sceneMapper;

    @Resource
    private SceneDetailMapper sceneDetailMapper;


    @Resource
    private ScoreRecordMapper scoreRecordMapper;

    @Resource
    private SparkService sparkService;

    @Resource
    private SceneRecordMapper sceneRecordMapper;

    @Override
    public List<Scene> all() {
        return sceneMapper.selectList(null);
    }

    @Override
    public SceneDetail chooseScene(int id) {
        LambdaQueryWrapper<SceneDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SceneDetail::getSceneId, id);
        SceneDetail one = sceneDetailMapper.selectOne(wrapper);
        return one;
    }

    @Override
    public SceneChatVO startChat(int id) {
        LambdaQueryWrapper<SceneDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SceneDetail::getSceneId, id);
        SceneDetail sceneDetail = sceneDetailMapper.selectOne(wrapper);
        String precondition = sceneDetail.getPrecondition();
        Integer userId = AuthContextUtil.get().getId();
        sparkService.chat(userId, precondition);
        String text = sceneDetail.getStart();
        byte[] audio = sparkService.tts(text);

        SceneChatVO sceneChatVO = new SceneChatVO();
        sceneChatVO.setText(text);
        sceneChatVO.setAudio(audio);

        new Thread(() -> {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = new Date();
            String formatDate = sdf.format(date);
            LambdaQueryWrapper<SceneRecord> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(SceneRecord::getSceneId, id);
            wrapper1.eq(SceneRecord::getUserId, userId);
            wrapper1.eq(SceneRecord::getDate, formatDate);
            SceneRecord sceneRecord = sceneRecordMapper.selectOne(wrapper1);
            if (ObjectUtil.isNull(sceneRecord)) {
                SceneRecord sceneRecord1 = new SceneRecord();
                sceneRecord1.setSceneId(id);
                sceneRecord1.setUserId(userId);
                sceneRecord1.setDate(formatDate);
                sceneRecordMapper.insert(sceneRecord1);
            }
        }).start();

        return sceneChatVO;
    }

    @Override
    public SpeakVO chat(MultipartFile file) {
        String reqText = sparkService.recognize(file);
//        for (char c : reqText.toCharArray()) {
//            if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
//                throw new BusinessException(ResultCodeEnum.AUDIO_ILLEGAL);
//            }
//        }
        Integer userId = AuthContextUtil.get().getId();
        String resText = sparkService.chat(userId, reqText);
        byte[] resAudio = sparkService.tts(resText);
        if (reqText.startsWith(" ")) {
            reqText = reqText.replaceFirst(" ", "");
        }
//        reqText = ("[content]\n" + reqText);
        byte[] bytes;
        try {
            bytes = AudioUtil.castToPcm(file);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        MockMultipartFile temp = new MockMultipartFile("./temp.pcm", bytes);

        ScoreVO scoreVO = sparkService.evaluate(temp, reqText);

        String reqTranslation;
        String resTranslation;
        try {
            reqTranslation = MachineTranslationUtil.translate(reqText);
            resTranslation = MachineTranslationUtil.translate(resText);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        SpeakVO speakVO = new SpeakVO();
        speakVO.setReqText(reqText);
        speakVO.setReqTranslation(reqTranslation);
        speakVO.setScoreVO(scoreVO);


        speakVO.setResText(resText);
        speakVO.setResTranslation(resTranslation);
        speakVO.setAudio(resAudio);
        return speakVO;
    }

    @Override
    @Transactional
    public SpeakVO sendMessage(MultipartFile file) {
        String reqText = sparkService.recognize(file);
//        for (char c : reqText.toCharArray()) {
//            if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
//                throw new BusinessException(ResultCodeEnum.AUDIO_ILLEGAL);
//            }
//        }
        if (reqText.startsWith(" ")) {
            reqText = reqText.replaceFirst(" ", "");
        }
//        byte[] bytes;
//        try {
//            bytes = AudioUtil.castToPcm(file);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//        MockMultipartFile temp = new MockMultipartFile("./temp.pcm", bytes);

        ScoreVO scoreVO = sparkService.evaluate(file, reqText);

        Integer userId = AuthContextUtil.get().getId();

        // 将得分情况保存
        ScoreRecord scoreRecord = new ScoreRecord();
        Integer totalScore = Integer.parseInt(scoreVO.getTotalScore().split("\\.")[0]);
        Integer accuracyScore = Integer.parseInt(scoreVO.getAccuracyScore().split("\\.")[0]);
        Integer fluencyScore = Integer.parseInt(scoreVO.getFluencyScore().split("\\.")[0]);
        Integer integrityScore = Integer.parseInt(scoreVO.getIntegrityScore().split("\\.")[0]);
        scoreRecord.setTotalScore(totalScore);
        scoreRecord.setAccuracyScore(accuracyScore);
        scoreRecord.setFluencyScore(fluencyScore);
        scoreRecord.setIntegrityScore(integrityScore);
        scoreRecord.setUserId(userId);
        scoreRecordMapper.insert(scoreRecord);


        String reqTranslation;
        try {
            reqTranslation = MachineTranslationUtil.translate(reqText);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        SpeakVO speakVO = new SpeakVO();
        speakVO.setReqText(reqText);
        speakVO.setReqTranslation(reqTranslation);
        speakVO.setScoreVO(scoreVO);

        return speakVO;
    }

    @Override
    public SpeakVO waitMsg(String msg) {
        Integer userId = AuthContextUtil.get().getId();
        String resText = sparkService.chat(userId, msg);
        byte[] resAudio = sparkService.tts(resText);
        String resTranslation;
        try {
            resTranslation = MachineTranslationUtil.translate(resText);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        SpeakVO speakVO = new SpeakVO();


        speakVO.setResText(resText);
        speakVO.setResTranslation(resTranslation);
        speakVO.setAudio(resAudio);
        return speakVO;
    }

    @Override
    public PageVo<Scene> sceneList(int categoryId, Integer pageNum, Integer pageSize) {
        PageVo<Scene> pageVo = new PageVo<>();


        if (categoryId == 1) {
            List<Scene> scenes = sceneMapper.selectList(null);
            pageVo.setRecords(scenes);
            return pageVo;
        }

        LambdaQueryWrapper<Scene> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Scene::getCategoryId, categoryId);
        if (pageNum != null && pageSize != null) {
            Page<Scene> page = new Page<>(pageNum, pageSize);
            List<Scene> records = page(page, wrapper).getRecords();
            pageVo.setTotal(page.getPages());
            pageVo.setRecords(records);
            return pageVo;
        }
        pageVo.setRecords(sceneMapper.selectList(wrapper));
        return pageVo;
    }

    @Override
    public String getAiPrompts(String msg) {

        String preCondition = "我们将进行角色扮演，现在我将传一段话给你，这句话是你说的但是我不会回答，请你帮我生成一句回答，要求使用英文回复，直接回答问题本身，不要说其他的。下面是我给你的一段话：";
        String res = sparkService.chat(9999, preCondition + msg);
        return res;
    }

    @Override
    public String check(String msg) {
        msg = msg + "对这句话进行语法纠错或者检查语句是否完整。按照以下几点来回答：原文翻译、语法纠错、正确句子、语法结构。";
        String res = sparkService.chat(9999, msg);
        return res;
    }

    @Override
    @Transactional
    public void delScene(Integer id) {
        removeById(id);
        LambdaQueryWrapper<SceneDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SceneDetail::getSceneId, id);
        sceneDetailMapper.delete(wrapper);
    }

    @Override
    @Transactional
    public void updateScene(SceneDto sceneDto) {
        Scene scene = BeanUtil.copyProperties(sceneDto, Scene.class);
        sceneMapper.updateById(scene);

        SceneDetail sceneDetail = BeanUtil.copyProperties(sceneDto, SceneDetail.class);
        sceneDetail.setSceneId(sceneDto.getId());
        sceneDetail.setId(null);
        LambdaQueryWrapper<SceneDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SceneDetail::getSceneId, sceneDto.getId());
        sceneDetailMapper.update(sceneDetail, wrapper);
    }

    @Override
    @Transactional
    public void insertBook(SceneDto sceneDto) {
        Scene scene = BeanUtil.copyProperties(sceneDto, Scene.class);
        scene.setId(null);
        sceneMapper.insert(scene);

        SceneDetail sceneDetail = BeanUtil.copyProperties(sceneDto, SceneDetail.class);
        sceneDetail.setSceneId(scene.getId());
        sceneDetail.setId(null);
        sceneDetailMapper.insert(sceneDetail);
    }

    @Override
    public SceneDto getSceneDetail(Integer id) {
        Scene scene = sceneMapper.selectById(id);
        SceneDetail sceneDetail = sceneDetailMapper.selectOne(new LambdaQueryWrapper<SceneDetail>().eq(SceneDetail::getSceneId, id));
        SceneDto sceneDto = new SceneDto();
        sceneDto.setId(scene.getId());
        sceneDto.setNameCn(scene.getNameCn());
        sceneDto.setNameEn(scene.getNameEn());
        sceneDto.setLogo(scene.getLogo());
        sceneDto.setDescription(sceneDetail.getDescription());
        sceneDto.setPrecondition(sceneDetail.getPrecondition());
        sceneDto.setAiRoleCn(sceneDetail.getAiRoleCn());
        sceneDto.setAiRoleEn(sceneDetail.getAiRoleEn());
        sceneDto.setUserRoleCn(sceneDetail.getUserRoleCn());
        sceneDto.setUserRoleEn(sceneDetail.getUserRoleEn());
        sceneDto.setStart(sceneDetail.getStart());
        return sceneDto;
    }
}




